﻿using System;
using System.IO;
using System.Web;
using System.Web.Mvc;

using Fuse8.DomainFramework.Common;

namespace Fuse8.ContentManagementFramework.Web.MvcPowered
{
    public class CmsMediaFileActionResult : FilePathResult
    {
        public bool BlockFromSearchEngines { get; set; }

        private HttpContextBase _httpContext;

        private readonly string _filePath;
        private int _mediaId;
        private int? _width;
        private int? _height;        

        public CmsMediaFileActionResult(HttpContextBase httpContext, int mediaId, string filePath, string fileDownloadName, int? width, int? height, string contentType = "image/jpeg")
            : base(filePath, contentType ?? "image/jpeg")
        {
            Guard.ArgumentNotNull(httpContext, "httpContext");

            _httpContext = httpContext;

            _filePath = filePath;
            _mediaId = mediaId;
            _width = width;
            _height = height;

            FileDownloadName = fileDownloadName;
        }

        public override void ExecuteResult(ControllerContext context)
        {
            if (File.Exists(_filePath))
            {
                var file = new FileInfo(_filePath);

                DateTime lastModified = file.LastWriteTimeUtc;
                string eTag = string.Format("{0}:{1}", _mediaId, lastModified.Ticks);
                if (_width.HasValue)
                {
                    eTag = string.Format("{0}:{1}", eTag, _width.Value);
                }
                if (_height.HasValue)
                {
                    eTag = string.Format("{0}:{1}", eTag, _height.Value);
                }
                eTag = string.Format(@"""{0}""", eTag);

                bool needProcess = true;
                if (_httpContext.Request.Headers["If-None-Match"] != null)
                {
                    if (_httpContext.Request.Headers["If-None-Match"].Equals(eTag, StringComparison.Ordinal))
                    {
                        needProcess = false;

                        _httpContext.Response.StatusCode = 304;
                        _httpContext.Response.Cache.SetETag(eTag);

                        if (_httpContext.Request.Headers["If-Modified-Since"] != null)
                        {
                            _httpContext.Response.Cache.SetLastModified(lastModified);
                        }
                    }
                }
                else if (_httpContext.Request.Headers["If-Modified-Since"] != null)
                {
                    DateTime dateModifiedSince = DateTime.MaxValue;
                    if (DateTime.TryParse(_httpContext.Request.Headers["If-Modified-Since"], out dateModifiedSince))
                    {
                        if (Math.Abs((lastModified - dateModifiedSince).Seconds) == 0)
                        {
                            needProcess = false;

                            _httpContext.Response.StatusCode = 304;
                            _httpContext.Response.Cache.SetLastModified(lastModified);
                        }
                    }
                }

                if (BlockFromSearchEngines)
                {
                    _httpContext.Response.AddHeader("X-Robots-Tag", "noindex");
                }

                if (needProcess)
                {
                    string fileLengthValue = file.Length.ToString();

                    _httpContext.Response.ContentType = ContentType;
                    _httpContext.Response.AppendHeader("Content-Disposition",
                        string.Format(@"inline; filename=""{0}""; size={1}", FileDownloadName, fileLengthValue));
                    _httpContext.Response.AppendHeader("Content-Length", fileLengthValue);                   

                    //common cache headers
                    _httpContext.Response.Cache.SetCacheability(HttpCacheability.ServerAndPrivate);
                    _httpContext.Response.Cache.SetRevalidation(HttpCacheRevalidation.AllCaches);
                    _httpContext.Response.Cache.SetLastModified(lastModified);
                    _httpContext.Response.Cache.SetETag(eTag);
                    _httpContext.Response.Cache.SetOmitVaryStar(true);

                    WriteFile(_httpContext.Response);
                }
            }
            else
            {
                _httpContext.Response.StatusCode = 404;
            }
        }
    }
}
